package com.upay.android.core.service;

import java.util.ArrayList;

import org.apache.http.NameValuePair;
import org.codehaus.jackson.type.TypeReference;

import android.os.AsyncTask;

import com.upay.android.client.handler.CallbackHandler;
import com.upay.android.domain.rest.RestRequest;
import com.upay.android.util.exception.RestException;
import com.upay.android.util.rest.RequestMethod;
import com.upay.android.util.rest.RestTemplate;
import com.upay.domain.response.ErrorType;
import com.upay.domain.response.ResponseEnvelope;

public class RestService<T extends Object> extends AsyncTask<String, Void, ResponseEnvelope<T>> {
	
	/* ---- Instance Variables ---- */
	private String url = null;
	private ArrayList<NameValuePair> params = null;
	private CallbackHandler<T> handler = null;
	private RequestMethod requestMethod = null;
	private RestException exception = null;
	private TypeReference<ResponseEnvelope<T>> typeReference = null;


	/* ---- Constructors ---- */
	public RestService(RestRequest restRequest, TypeReference<ResponseEnvelope<T>> typeReference, CallbackHandler<T> handler) {
		super();
		this.handler = handler;
		this.url = restRequest.getUrl();
		this.requestMethod = restRequest.getRequestMethod();
		this.params = restRequest.getParams();
		this.typeReference = typeReference;
	}
		

	/* ---- Business Methods ---- */
	
	public void execute() {
		this.execute(new String[] {});
	}

	@Override
	protected ResponseEnvelope<T> doInBackground(String... parameters) {
		ResponseEnvelope<T> responseEnvelope =  null;
		try {
            RestTemplate<T> template = new RestTemplate<T>();
            responseEnvelope = template.getForEntity(this.url, this.requestMethod, this.params, this.typeReference);
		} catch (RestException restException) {
			this.exception = restException;
		}
		return responseEnvelope;
	}

	@Override
	protected void onPostExecute(ResponseEnvelope<T> response) {
		if (exception == null) {
			if (!response.getResponseHeader().getStatus()) {
				if (ErrorType.PROGRAM_ERROR.equals(response.getResponseBody().getResponseError().getType())) {
					this.handler.handleProgramException(response);
				}
				if (ErrorType.VALIDATION_ERROR.equals(response.getResponseBody().getResponseError().getType())) {
					this.handler.handleValidationException(response);
				}
			} else {
			    this.handler.handleResponse(response);
			}
		} else {
			this.handler.handleRestException(exception);
		}
		
	}
	
	
	/* ---- Getters and Setters ---- */


	/**
	 * @return the url
	 */
	public String getUrl() {
		return url;
	}


	/**
	 * @param url the url to set
	 */
	public void setUrl(String url) {
		this.url = url;
	}


	/**
	 * @return the params
	 */
	public ArrayList<NameValuePair> getParams() {
		return params;
	}


	/**
	 * @param params the params to set
	 */
	public void setParams(ArrayList<NameValuePair> params) {
		this.params = params;
	}

	/**
	 * @return the requestMethod
	 */
	public RequestMethod getRequestMethod() {
		return requestMethod;
	}


	/**
	 * @param requestMethod the requestMethod to set
	 */
	public void setRequestMethod(RequestMethod requestMethod) {
		this.requestMethod = requestMethod;
	}


	/**
	 * @return the exception
	 */
	public RestException getException() {
		return exception;
	}


	/**
	 * @param exception the exception to set
	 */
	public void setException(RestException exception) {
		this.exception = exception;
	}


	/**
	 * @return the typeReference
	 */
	public TypeReference<ResponseEnvelope<T>> getTypeReference() {
		return typeReference;
	}


	/**
	 * @param typeReference the typeReference to set
	 */
	public void setTypeReference(TypeReference<ResponseEnvelope<T>> typeReference) {
		this.typeReference = typeReference;
	}


	/**
	 * @return the handler
	 */
	protected CallbackHandler<T> getHandler() {
		return handler;
	}


	/**
	 * @param handler the handler to set
	 */
	protected void setHandler(CallbackHandler<T> handler) {
		this.handler = handler;
	}


}
